#ifndef _CLASSLITERAL_HPP
#define _CLASSLITERAL_HPP

#include <string>
#include "Token.hpp"
#include "Expression.hpp"
#include "Identifier.hpp"
#include <map>
#include <vector>
#include <algorithm>

namespace ast {
	class ClassLiteral : public Expression {
	public:
		ClassLiteral(TOKEN token) {
			_token = token;
		}

		virtual void ExpressionNode() override {}


		virtual string tokenLiteral() override {
			return _token._literal;
		}

		virtual string String() override {
			string out;
			string tab = "    ";
			_depth++;
			out.append(_token._literal);
			out.append(" " + _className->String());
			out.append(" {\n");
			size_t member_size = _properties.size();
			if (member_size) {
				std::vector<std::pair<Identifier*, Expression*>> args(_properties.begin(), _properties.end());
				std::sort(args.begin(), args.end(), [](auto& a, auto& b) {
					return a.first->String() < b.first->String();
				});
				for (auto& itr : args) {
					for (int i = 0; i < _depth; i++) {
						out.append(tab);
					}
					out.append(itr.first->String());
					if (itr.second != nullptr) {
						out.append(" = ");
						out.append(itr.second->String());
					}
					out.append(";");
					out.append("\n");
				}
			}
			size_t method_size = _methods.size();
			if (method_size) {
				std::vector<std::pair<Identifier*, Expression*>> args(_methods.begin(), _methods.end());
				std::sort(args.begin(), args.end(), [](auto& a, auto& b) {
					return a.first->String() < b.first->String();
				});
				for (auto& itr : args) {
					out.append(itr.second->String());
					out.append("\n");
				}
			}
			out.append("}");
			_depth--;
			return out;
		}

		virtual ~ClassLiteral() {
			if (_className != nullptr) {
				delete _className;
			}

			if (_properties.size()) {
				for (auto&itr : _properties) {
					if (itr.first != nullptr) {
						delete itr.first;
					}
					if (itr.second != nullptr) {
						delete itr.second;
					}
				}
				_properties.clear();
			}

			if (_methods.size()) {
				for (auto& itr : _methods) {
					if (itr.first != nullptr) {
						delete itr.first;
					}
					if (itr.second != nullptr) {
						delete itr.second;
					}
				}
				_methods.clear();
			}
		}

	public:
		TOKEN _token;
		Identifier* _className{ nullptr };
		std::map<Identifier*, Expression*> _properties;
		std::map<Identifier*, Expression*> _methods;
	};
}

#endif